home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Tk / generic / tkImgBmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-31  |  30.0 KB  |  1,025 lines

  1. /* 
  2.  * tkImgBmap.c --
  3.  *
  4.  *    This procedure implements images of type "bitmap" for Tk.
  5.  *
  6.  * Copyright (c) 1994 The Regents of the University of California.
  7.  * Copyright (c) 1994-1996 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkImgBmap.c 1.26 96/02/15 18:53:36
  13.  */
  14.  
  15. #include "tkInt.h"
  16. #include "tkPort.h"
  17.  
  18. /*
  19.  * The following data structure represents the master for a bitmap
  20.  * image:
  21.  */
  22.  
  23. typedef struct BitmapMaster {
  24.     Tk_ImageMaster tkMaster;    /* Tk's token for image master.  NULL means
  25.                  * the image is being deleted. */
  26.     Tcl_Interp *interp;        /* Interpreter for application that is
  27.                  * using image. */
  28.     Tcl_Command imageCmd;    /* Token for image command (used to delete
  29.                  * it when the image goes away).  NULL means
  30.                  * the image command has already been
  31.                  * deleted. */
  32.     int width, height;        /* Dimensions of image. */
  33.     char *data;            /* Data comprising bitmap (suitable for
  34.                  * input to XCreateBitmapFromData).   May
  35.                  * be NULL if no data.  Malloc'ed. */
  36.     char *maskData;        /* Data for bitmap's mask (suitable for
  37.                  * input to XCreateBitmapFromData).
  38.                  * Malloc'ed. */
  39.     Tk_Uid fgUid;        /* Value of -foreground option (malloc'ed). */
  40.     Tk_Uid bgUid;        /* Value of -background option (malloc'ed). */
  41.     char *fileString;        /* Value of -file option (malloc'ed). */
  42.     char *dataString;        /* Value of -data option (malloc'ed). */
  43.     char *maskFileString;    /* Value of -maskfile option (malloc'ed). */
  44.     char *maskDataString;    /* Value of -maskdata option (malloc'ed). */
  45.     struct BitmapInstance *instancePtr;
  46.                 /* First in list of all instances associated
  47.                  * with this master. */
  48. } BitmapMaster;
  49.  
  50. /*
  51.  * The following data structure represents all of the instances of an
  52.  * image that lie within a particular window:
  53.  */
  54.  
  55. typedef struct BitmapInstance {
  56.     int refCount;        /* Number of instances that share this
  57.                  * data structure. */
  58.     BitmapMaster *masterPtr;    /* Pointer to master for image. */
  59.     Tk_Window tkwin;        /* Window in which the instances will be
  60.                  * displayed. */
  61.     XColor *fg;            /* Foreground color for displaying image. */
  62.     XColor *bg;            /* Background color for displaying image. */
  63.     Pixmap bitmap;        /* The bitmap to display. */
  64.     Pixmap mask;        /* Mask: only display bitmap pixels where
  65.                  * there are 1's here. */
  66.     GC gc;            /* Graphics context for displaying bitmap.
  67.                  * None means there was an error while
  68.                  * setting up the instance, so it cannot
  69.                  * be displayed. */
  70.     struct BitmapInstance *nextPtr;
  71.                 /* Next in list of all instance structures
  72.                  * associated with masterPtr (NULL means
  73.                  * end of list). */
  74. } BitmapInstance;
  75.  
  76. /*
  77.  * The type record for bitmap images:
  78.  */
  79.  
  80. static int        ImgBmapCreate _ANSI_ARGS_((Tcl_Interp *interp,
  81.                 char *name, int argc, char **argv,
  82.                 Tk_ImageType *typePtr, Tk_ImageMaster master,
  83.                 ClientData *clientDataPtr));
  84. static ClientData    ImgBmapGet _ANSI_ARGS_((Tk_Window tkwin,
  85.                 ClientData clientData));
  86. static void        ImgBmapDisplay _ANSI_ARGS_((ClientData clientData,
  87.                 Display *display, Drawable drawable, 
  88.                 int imageX, int imageY, int width, int height,
  89.                 int drawableX, int drawableY));
  90. static void        ImgBmapFree _ANSI_ARGS_((ClientData clientData,
  91.                 Display *display));
  92. static void        ImgBmapDelete _ANSI_ARGS_((ClientData clientData));
  93.  
  94. Tk_ImageType tkBitmapImageType = {
  95.     "bitmap",            /* name */
  96.     ImgBmapCreate,        /* createProc */
  97.     ImgBmapGet,            /* getProc */
  98.     ImgBmapDisplay,        /* displayProc */
  99.     ImgBmapFree,        /* freeProc */
  100.     ImgBmapDelete,        /* deleteProc */
  101.     (Tk_ImageType *) NULL    /* nextPtr */
  102. };
  103.  
  104. /*
  105.  * Information used for parsing configuration specs:
  106.  */
  107.  
  108. static Tk_ConfigSpec configSpecs[] = {
  109.     {TK_CONFIG_UID, "-background", (char *) NULL, (char *) NULL,
  110.     "", Tk_Offset(BitmapMaster, bgUid), 0},
  111.     {TK_CONFIG_STRING, "-data", (char *) NULL, (char *) NULL,
  112.     (char *) NULL, Tk_Offset(BitmapMaster, dataString), TK_CONFIG_NULL_OK},
  113.     {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL,
  114.     (char *) NULL, Tk_Offset(BitmapMaster, fileString), TK_CONFIG_NULL_OK},
  115.     {TK_CONFIG_UID, "-foreground", (char *) NULL, (char *) NULL,
  116.     "#000000", Tk_Offset(BitmapMaster, fgUid), 0},
  117.     {TK_CONFIG_STRING, "-maskdata", (char *) NULL, (char *) NULL,
  118.     (char *) NULL, Tk_Offset(BitmapMaster, maskDataString),
  119.     TK_CONFIG_NULL_OK},
  120.     {TK_CONFIG_STRING, "-maskfile", (char *) NULL, (char *) NULL,
  121.     (char *) NULL, Tk_Offset(BitmapMaster, maskFileString),
  122.     TK_CONFIG_NULL_OK},
  123.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  124.     (char *) NULL, 0, 0}
  125. };
  126.  
  127. /*
  128.  * The following data structure is used to describe the state of
  129.  * parsing a bitmap file or string.  It is used for communication
  130.  * between TkGetBitmapData and NextBitmapWord.
  131.  */
  132.  
  133. #define MAX_WORD_LENGTH 100
  134. typedef struct ParseInfo {
  135.     char *string;        /* Next character of string data for bitmap,
  136.                  * or NULL if bitmap is being read from
  137.                  * file. */
  138.     FILE *f;            /* File containing bitmap data, or NULL
  139.                  * if no file. */
  140.     char word[MAX_WORD_LENGTH+1];
  141.                 /* Current word of bitmap data, NULL
  142.                  * terminated. */
  143.     int wordLength;        /* Number of non-NULL bytes in word. */
  144. } ParseInfo;
  145.  
  146. /*
  147.  * Prototypes for procedures used only locally in this file:
  148.  */
  149.  
  150. static int        ImgBmapCmd _ANSI_ARGS_((ClientData clientData,
  151.                 Tcl_Interp *interp, int argc, char **argv));
  152. static void        ImgBmapCmdDeletedProc _ANSI_ARGS_((
  153.                 ClientData clientData));
  154. static void        ImgBmapConfigureInstance _ANSI_ARGS_((
  155.                 BitmapInstance *instancePtr));
  156. static int        ImgBmapConfigureMaster _ANSI_ARGS_((
  157.                 BitmapMaster *masterPtr, int argc, char **argv,
  158.                 int flags));
  159. static int        NextBitmapWord _ANSI_ARGS_((ParseInfo *parseInfoPtr));
  160.  
  161. /*
  162.  *----------------------------------------------------------------------
  163.  *
  164.  * ImgBmapCreate --
  165.  *
  166.  *    This procedure is called by the Tk image code to create "test"
  167.  *    images.
  168.  *
  169.  * Results:
  170.  *    A standard Tcl result.
  171.  *
  172.  * Side effects:
  173.  *    The data structure for a new image is allocated.
  174.  *
  175.  *----------------------------------------------------------------------
  176.  */
  177.  
  178.     /* ARGSUSED */
  179. static int
  180. ImgBmapCreate(interp, name, argc, argv, typePtr, master, clientDataPtr)
  181.     Tcl_Interp *interp;        /* Interpreter for application containing
  182.                  * image. */
  183.     char *name;            /* Name to use for image. */
  184.     int argc;            /* Number of arguments. */
  185.     char **argv;        /* Argument strings for options (doesn't
  186.                  * include image name or type). */
  187.     Tk_ImageType *typePtr;    /* Pointer to our type record (not used). */
  188.     Tk_ImageMaster master;    /* Token for image, to be used by us in
  189.                  * later callbacks. */
  190.     ClientData *clientDataPtr;    /* Store manager's token for image here;
  191.                  * it will be returned in later callbacks. */
  192. {
  193.     BitmapMaster *masterPtr;
  194.  
  195.     masterPtr = (BitmapMaster *) ckalloc(sizeof(BitmapMaster));
  196.     masterPtr->tkMaster = master;
  197.     masterPtr->interp = interp;
  198.     masterPtr->imageCmd = Tcl_CreateCommand(interp, name, ImgBmapCmd,
  199.         (ClientData) masterPtr, ImgBmapCmdDeletedProc);
  200.     masterPtr->width = masterPtr->height = 0;
  201.     masterPtr->data = NULL;
  202.     masterPtr->maskData = NULL;
  203.     masterPtr->fgUid = NULL;
  204.     masterPtr->bgUid = NULL;
  205.     masterPtr->fileString = NULL;
  206.     masterPtr->dataString = NULL;
  207.     masterPtr->maskFileString = NULL;
  208.     masterPtr->maskDataString = NULL;
  209.     masterPtr->instancePtr = NULL;
  210.     if (ImgBmapConfigureMaster(masterPtr, argc, argv, 0) != TCL_OK) {
  211.     ImgBmapDelete((ClientData) masterPtr);
  212.     return TCL_ERROR;
  213.     }
  214.     *clientDataPtr = (ClientData) masterPtr;
  215.     return TCL_OK;
  216. }
  217.  
  218. /*
  219.  *----------------------------------------------------------------------
  220.  *
  221.  * ImgBmapConfigureMaster --
  222.  *
  223.  *    This procedure is called when a bitmap image is created or
  224.  *    reconfigured.  It process configuration options and resets
  225.  *    any instances of the image.
  226.  *
  227.  * Results:
  228.  *    A standard Tcl return value.  If TCL_ERROR is returned then
  229.  *    an error message is left in masterPtr->interp->result.
  230.  *
  231.  * Side effects:
  232.  *    Existing instances of the image will be redisplayed to match
  233.  *    the new configuration options.
  234.  *
  235.  *----------------------------------------------------------------------
  236.  */
  237.  
  238. static int
  239. ImgBmapConfigureMaster(masterPtr, argc, argv, flags)
  240.     BitmapMaster *masterPtr;    /* Pointer to data structure describing
  241.                  * overall bitmap image to (reconfigure). */
  242.     int argc;            /* Number of entries in argv. */
  243.     char **argv;        /* Pairs of configuration options for image. */
  244.     int flags;            /* Flags to pass to Tk_ConfigureWidget,
  245.                  * such as TK_CONFIG_ARGV_ONLY. */
  246. {
  247.     BitmapInstance *instancePtr;
  248.     int maskWidth, maskHeight, dummy1, dummy2;
  249.  
  250.     if (Tk_ConfigureWidget(masterPtr->interp, Tk_MainWindow(masterPtr->interp),
  251.         configSpecs, argc, argv, (char *) masterPtr, flags)
  252.         != TCL_OK) {
  253.     return TCL_ERROR;
  254.     }
  255.  
  256.     /*
  257.      * Parse the bitmap and/or mask to create binary data.  Make sure that
  258.      * the bitmap and mask have the same dimensions.
  259.      */
  260.  
  261.     if (masterPtr->data != NULL) {
  262.     ckfree(masterPtr->data);
  263.     masterPtr->data = NULL;
  264.     }
  265.     if ((masterPtr->fileString != NULL) || (masterPtr->dataString != NULL)) {
  266.     masterPtr->data = TkGetBitmapData(masterPtr->interp,
  267.         masterPtr->dataString, masterPtr->fileString,
  268.         &masterPtr->width, &masterPtr->height, &dummy1, &dummy2);
  269.     if (masterPtr->data == NULL) {
  270.         return TCL_ERROR;
  271.     }
  272.     }
  273.     if (masterPtr->maskData != NULL) {
  274.     ckfree(masterPtr->maskData);
  275.     masterPtr->maskData = NULL;
  276.     }
  277.     if ((masterPtr->maskFileString != NULL)
  278.         || (masterPtr->maskDataString != NULL)) {
  279.     if (masterPtr->data == NULL) {
  280.         masterPtr->interp->result = "can't have mask without bitmap";
  281.         return TCL_ERROR;
  282.     }
  283.     masterPtr->maskData = TkGetBitmapData(masterPtr->interp,
  284.         masterPtr->maskDataString, masterPtr->maskFileString,
  285.         &maskWidth, &maskHeight, &dummy1, &dummy2);
  286.     if (masterPtr->maskData == NULL) {
  287.         return TCL_ERROR;
  288.     }
  289.     if ((maskWidth != masterPtr->width)
  290.         || (maskHeight != masterPtr->height)) {
  291.         ckfree(masterPtr->maskData);
  292.         masterPtr->maskData = NULL;
  293.         masterPtr->interp->result = "bitmap and mask have different sizes";
  294.         return TCL_ERROR;
  295.     }
  296.     }
  297.  
  298.     /*
  299.      * Cycle through all of the instances of this image, regenerating
  300.      * the information for each instance.  Then force the image to be
  301.      * redisplayed everywhere that it is used.
  302.      */
  303.  
  304.     for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
  305.         instancePtr = instancePtr->nextPtr) {
  306.     ImgBmapConfigureInstance(instancePtr);
  307.     }
  308.     Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width,
  309.         masterPtr->height, masterPtr->width, masterPtr->height);
  310.     return TCL_OK;
  311. }
  312.  
  313. /*
  314.  *----------------------------------------------------------------------
  315.  *
  316.  * ImgBmapConfigureInstance --
  317.  *
  318.  *    This procedure is called to create displaying information for
  319.  *    a bitmap image instance based on the configuration information
  320.  *    in the master.  It is invoked both when new instances are
  321.  *    created and when the master is reconfigured.
  322.  *
  323.  * Results:
  324.  *    None.
  325.  *
  326.  * Side effects:
  327.  *    Generates errors via Tcl_BackgroundError if there are problems
  328.  *    in setting up the instance.
  329.  *
  330.  *----------------------------------------------------------------------
  331.  */
  332.  
  333. static void
  334. ImgBmapConfigureInstance(instancePtr)
  335.     BitmapInstance *instancePtr;    /* Instance to reconfigure. */
  336. {
  337.     BitmapMaster *masterPtr = instancePtr->masterPtr;
  338.     XColor *colorPtr;
  339.     XGCValues gcValues;
  340.     GC gc;
  341.     unsigned int mask;
  342.  
  343.     /*
  344.      * For each of the options in masterPtr, translate the string
  345.      * form into an internal form appropriate for instancePtr.
  346.      */
  347.  
  348.     if (*masterPtr->bgUid != 0) {
  349.     colorPtr = Tk_GetColor(masterPtr->interp, instancePtr->tkwin,
  350.         masterPtr->bgUid);
  351.     if (colorPtr == NULL) {
  352.         goto error;
  353.     }
  354.     } else {
  355.     colorPtr = NULL;
  356.     }
  357.     if (instancePtr->bg != NULL) {
  358.     Tk_FreeColor(instancePtr->bg);
  359.     }
  360.     instancePtr->bg = colorPtr;
  361.  
  362.     colorPtr = Tk_GetColor(masterPtr->interp, instancePtr->tkwin,
  363.         masterPtr->fgUid);
  364.     if (colorPtr == NULL) {
  365.     goto error;
  366.     }
  367.     if (instancePtr->fg != NULL) {
  368.     Tk_FreeColor(instancePtr->fg);
  369.     }
  370.     instancePtr->fg = colorPtr;
  371.  
  372.     if (instancePtr->bitmap != None) {
  373.     XFreePixmap(Tk_Display(instancePtr->tkwin), instancePtr->bitmap);
  374.     instancePtr->bitmap = None;
  375.     }
  376.     if (masterPtr->data != NULL) {
  377.     instancePtr->bitmap = XCreateBitmapFromData(
  378.         Tk_Display(instancePtr->tkwin),
  379.         RootWindowOfScreen(Tk_Screen(instancePtr->tkwin)),
  380.         masterPtr->data, (unsigned) masterPtr->width,
  381.         (unsigned) masterPtr->height);
  382.     }
  383.  
  384.     if (instancePtr->mask != None) {
  385.     XFreePixmap(Tk_Display(instancePtr->tkwin), instancePtr->mask);
  386.     instancePtr->mask = None;
  387.     }
  388.     if (masterPtr->maskData != NULL) {
  389.     instancePtr->mask = XCreateBitmapFromData(
  390.         Tk_Display(instancePtr->tkwin),
  391.         RootWindowOfScreen(Tk_Screen(instancePtr->tkwin)),
  392.         masterPtr->maskData, (unsigned) masterPtr->width,
  393.         (unsigned) masterPtr->height);
  394.     }
  395.  
  396.     if (masterPtr->data != NULL) {
  397.     gcValues.foreground = instancePtr->fg->pixel;
  398.     gcValues.graphics_exposures = False;
  399.     mask = GCForeground|GCGraphicsExposures;
  400.     if (instancePtr->bg != NULL) {
  401.         gcValues.background = instancePtr->bg->pixel;
  402.         mask |= GCBackground;
  403.         if (instancePtr->mask != None) {
  404.         gcValues.clip_mask = instancePtr->mask;
  405.         mask |= GCClipMask;
  406.         }
  407.     } else {
  408.         gcValues.clip_mask = instancePtr->bitmap;
  409.         mask |= GCClipMask;
  410.     }
  411.     gc = Tk_GetGC(instancePtr->tkwin, mask, &gcValues);
  412.     } else {
  413.     gc = None;
  414.     }
  415.     if (instancePtr->gc != None) {
  416.     Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc);
  417.     }
  418.     instancePtr->gc = gc;
  419.     return;
  420.  
  421.     error:
  422.     /*
  423.      * An error occurred: clear the graphics context in the instance to
  424.      * make it clear that this instance cannot be displayed.  Then report
  425.      * the error.
  426.      */
  427.  
  428.     if (instancePtr->gc != None) {
  429.     Tk_FreeGC(Tk_Display(instancePtr->tkwin), instancePtr->gc);
  430.     }
  431.     instancePtr->gc = None;
  432.     Tcl_AddErrorInfo(masterPtr->interp, "\n    (while configuring image \"");
  433.     Tcl_AddErrorInfo(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
  434.     Tcl_AddErrorInfo(masterPtr->interp, "\")");
  435.     Tcl_BackgroundError(masterPtr->interp);
  436. }
  437.  
  438. /*
  439.  *----------------------------------------------------------------------
  440.  *
  441.  * TkGetBitmapData --
  442.  *
  443.  *    Given a file name or ASCII string, this procedure parses the
  444.  *    file or string contents to produce binary data for a bitmap.
  445.  *
  446.  * Results:
  447.  *    If the bitmap description was parsed successfully then the
  448.  *    return value is a malloc-ed array containing the bitmap data.
  449.  *    The dimensions of the data are stored in *widthPtr and
  450.  *    *heightPtr.  *hotXPtr and *hotYPtr are set to the bitmap
  451.  *    hotspot if one is defined, otherwise they are set to -1, -1.
  452.  *    If an error occurred, NULL is returned and an error message is
  453.  *    left in interp->result.
  454.  *
  455.  * Side effects:
  456.  *    A bitmap is created.
  457.  *
  458.  *----------------------------------------------------------------------
  459.  */
  460.  
  461. char *
  462. TkGetBitmapData(interp, string, fileName, widthPtr, heightPtr,
  463.     hotXPtr, hotYPtr)
  464.     Tcl_Interp *interp;            /* For reporting errors. */
  465.     char *string;            /* String describing bitmap.  May
  466.                      * be NULL. */
  467.     char *fileName;            /* Name of file containing bitmap
  468.                      * description.  Used only if string
  469.                      * is NULL.  Must not be NULL if
  470.                      * string is NULL. */
  471.     int *widthPtr, *heightPtr;        /* Dimensions of bitmap get returned
  472.                      * here. */
  473.     int *hotXPtr, *hotYPtr;        /* Position of hot spot or -1,-1. */
  474. {
  475.     int width, height, numBytes, hotX, hotY;
  476.     char *p, *end, *expandedFileName;
  477.     ParseInfo pi;
  478.     char *data = NULL;
  479.     Tcl_DString buffer;
  480.  
  481.     pi.string = string;
  482.     if (string == NULL) {
  483.     expandedFileName = Tcl_TranslateFileName(interp, fileName, &buffer);
  484.     if (expandedFileName == NULL) {
  485.         return NULL;
  486.     }
  487.     pi.f = fopen(expandedFileName, "r");
  488.     Tcl_DStringFree(&buffer);
  489.     if (pi.f == NULL) {
  490.         Tcl_AppendResult(interp, "couldn't read bitmap file \"",
  491.             fileName, "\": ", Tcl_PosixError(interp), (char *) NULL);
  492.         return NULL;
  493.     }
  494.     } else {
  495.     pi.f = NULL;
  496.     }
  497.  
  498.     /*
  499.      * Parse the lines that define the dimensions of the bitmap,
  500.      * plus the first line that defines the bitmap data (it declares
  501.      * the name of a data variable but doesn't include any actual
  502.      * data).  These lines look something like the following:
  503.      *
  504.      *        #define foo_width 16
  505.      *        #define foo_height 16
  506.      *        #define foo_x_hot 3
  507.      *        #define foo_y_hot 3
  508.      *        static char foo_bits[] = {
  509.      *
  510.      * The x_hot and y_hot lines may or may not be present.  It's
  511.      * important to check for "char" in the last line, in order to
  512.      * reject old X10-style bitmaps that used shorts.
  513.      */
  514.  
  515.     width = 0;
  516.     height = 0;
  517.     hotX = -1;
  518.     hotY = -1;
  519.     while (1) {
  520.     if (NextBitmapWord(&pi) != TCL_OK) {
  521.         goto error;
  522.     }
  523.     if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_')
  524.         && (strcmp(pi.word+pi.wordLength-6, "_width") == 0)) {
  525.         if (NextBitmapWord(&pi) != TCL_OK) {
  526.         goto error;
  527.         }
  528.         width = strtol(pi.word, &end, 0);
  529.         if ((end == pi.word) || (*end != 0)) {
  530.         goto error;
  531.         }
  532.     } else if ((pi.wordLength >= 7) && (pi.word[pi.wordLength-7] == '_')
  533.         && (strcmp(pi.word+pi.wordLength-7, "_height") == 0)) {
  534.         if (NextBitmapWord(&pi) != TCL_OK) {
  535.         goto error;
  536.         }
  537.         height = strtol(pi.word, &end, 0);
  538.         if ((end == pi.word) || (*end != 0)) {
  539.         goto error;
  540.         }
  541.     } else if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_')
  542.         && (strcmp(pi.word+pi.wordLength-6, "_x_hot") == 0)) {
  543.         if (NextBitmapWord(&pi) != TCL_OK) {
  544.         goto error;
  545.         }
  546.         hotX = strtol(pi.word, &end, 0);
  547.         if ((end == pi.word) || (*end != 0)) {
  548.         goto error;
  549.         }
  550.     } else if ((pi.wordLength >= 6) && (pi.word[pi.wordLength-6] == '_')
  551.         && (strcmp(pi.word+pi.wordLength-6, "_y_hot") == 0)) {
  552.         if (NextBitmapWord(&pi) != TCL_OK) {
  553.         goto error;
  554.         }
  555.         hotY = strtol(pi.word, &end, 0);
  556.         if ((end == pi.word) || (*end != 0)) {
  557.         goto error;
  558.         }
  559.     } else if ((pi.word[0] == 'c') && (strcmp(pi.word, "char") == 0)) {
  560.         while (1) {
  561.         if (NextBitmapWord(&pi) != TCL_OK) {
  562.             goto error;
  563.         }
  564.         if ((pi.word[0] == '{') && (pi.word[1] == 0)) {
  565.             goto getData;
  566.         }
  567.         }
  568.     } else if ((pi.word[0] == '{') && (pi.word[1] == 0)) {
  569.         Tcl_AppendResult(interp, "format error in bitmap data; ",
  570.             "looks like it's an obsolete X10 bitmap file",
  571.             (char *) NULL);
  572.         goto errorCleanup;
  573.     }
  574.     }
  575.  
  576.     /*
  577.      * Now we've read everything but the data.  Allocate an array
  578.      * and read in the data.
  579.      */
  580.  
  581.     getData:
  582.     if ((width <= 0) || (height <= 0)) {
  583.     goto error;
  584.     }
  585.     numBytes = ((width+7)/8) * height;
  586.     data = (char *) ckalloc((unsigned) numBytes);
  587.     for (p = data; numBytes > 0; p++, numBytes--) {
  588.     if (NextBitmapWord(&pi) != TCL_OK) {
  589.         goto error;
  590.     }
  591.     *p = strtol(pi.word, &end, 0);
  592.     if (end == pi.word) {
  593.         goto error;
  594.     }
  595.     }
  596.  
  597.     /*
  598.      * All done.  Clean up and return.
  599.      */
  600.  
  601.     if (pi.f != NULL) {
  602.     fclose(pi.f);
  603.     }
  604.     *widthPtr = width;
  605.     *heightPtr = height;
  606.     *hotXPtr = hotX;
  607.     *hotYPtr = hotY;
  608.     return data;
  609.  
  610.     error:
  611.     interp->result = "format error in bitmap data";
  612.     errorCleanup:
  613.     if (data != NULL) {
  614.     ckfree(data);
  615.     }
  616.     if (pi.f != NULL) {
  617.     fclose(pi.f);
  618.     }
  619.     return NULL;
  620. }
  621.  
  622. /*
  623.  *----------------------------------------------------------------------
  624.  *
  625.  * NextBitmapWord --
  626.  *
  627.  *    This procedure retrieves the next word of information (stuff
  628.  *    between commas or white space) from a bitmap description.
  629.  *
  630.  * Results:
  631.  *    Returns TCL_OK if all went well.  In this case the next word,
  632.  *    and its length, will be availble in *parseInfoPtr.  If the end
  633.  *    of the bitmap description was reached then TCL_ERROR is returned.
  634.  *
  635.  * Side effects:
  636.  *    None.
  637.  *
  638.  *----------------------------------------------------------------------
  639.  */
  640.  
  641. static int
  642. NextBitmapWord(parseInfoPtr)
  643.     ParseInfo *parseInfoPtr;        /* Describes what we're reading
  644.                      * and where we are in it. */
  645. {
  646.     char *src, *dst;
  647.     int c;
  648.  
  649.     parseInfoPtr->wordLength = 0;
  650.     dst = parseInfoPtr->word;
  651.     if (parseInfoPtr->string != NULL) {
  652.     for (src = parseInfoPtr->string; isspace(UCHAR(*src)) || (*src == ',');
  653.         src++) {
  654.         if (*src == 0) {
  655.         return TCL_ERROR;
  656.         }
  657.     }
  658.     for ( ; !isspace(UCHAR(*src)) && (*src != ',') && (*src != 0); src++) {
  659.         *dst = *src;
  660.         dst++;
  661.         parseInfoPtr->wordLength++;
  662.         if (parseInfoPtr->wordLength > MAX_WORD_LENGTH) {
  663.         return TCL_ERROR;
  664.         }
  665.     }
  666.     parseInfoPtr->string = src;
  667.     } else {
  668.     for (c = getc(parseInfoPtr->f); isspace(UCHAR(c)) || (c == ',');
  669.         c = getc(parseInfoPtr->f)) {
  670.         if (c == EOF) {
  671.         return TCL_ERROR;
  672.         }
  673.     }
  674.     for ( ; !isspace(UCHAR(c)) && (c != ',') && (c != EOF);
  675.         c = getc(parseInfoPtr->f)) {
  676.         *dst = c;
  677.         dst++;
  678.         parseInfoPtr->wordLength++;
  679.         if (parseInfoPtr->wordLength > MAX_WORD_LENGTH) {
  680.         return TCL_ERROR;
  681.         }
  682.     }
  683.     }
  684.     if (parseInfoPtr->wordLength == 0) {
  685.     return TCL_ERROR;
  686.     }
  687.     parseInfoPtr->word[parseInfoPtr->wordLength] = 0;
  688.     return TCL_OK;
  689. }
  690.  
  691. /*
  692.  *--------------------------------------------------------------
  693.  *
  694.  * ImgBmapCmd --
  695.  *
  696.  *    This procedure is invoked to process the Tcl command
  697.  *    that corresponds to an image managed by this module.
  698.  *    See the user documentation for details on what it does.
  699.  *
  700.  * Results:
  701.  *    A standard Tcl result.
  702.  *
  703.  * Side effects:
  704.  *    See the user documentation.
  705.  *
  706.  *--------------------------------------------------------------
  707.  */
  708.  
  709. static int
  710. ImgBmapCmd(clientData, interp, argc, argv)
  711.     ClientData clientData;    /* Information about button widget. */
  712.     Tcl_Interp *interp;        /* Current interpreter. */
  713.     int argc;            /* Number of arguments. */
  714.     char **argv;        /* Argument strings. */
  715. {
  716.     BitmapMaster *masterPtr = (BitmapMaster *) clientData;
  717.     int c, code;
  718.     size_t length;
  719.  
  720.     if (argc < 2) {
  721.     sprintf(interp->result,
  722.         "wrong # args: should be \"%.50s option ?arg arg ...?\"",
  723.         argv[0]);
  724.     return TCL_ERROR;
  725.     }
  726.     c = argv[1][0];
  727.     length = strlen(argv[1]);
  728.     if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
  729.         && (length >= 2)) {
  730.     if (argc != 3) {
  731.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  732.             argv[0], " cget option\"",
  733.             (char *) NULL);
  734.         return TCL_ERROR;
  735.     }
  736.     return Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
  737.         (char *) masterPtr, argv[2], 0);
  738.     } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
  739.         && (length >= 2)) {
  740.     if (argc == 2) {
  741.         code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
  742.             configSpecs, (char *) masterPtr, (char *) NULL, 0);
  743.     } else if (argc == 3) {
  744.         code = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
  745.             configSpecs, (char *) masterPtr, argv[2], 0);
  746.     } else {
  747.         code = ImgBmapConfigureMaster(masterPtr, argc-2, argv+2,
  748.             TK_CONFIG_ARGV_ONLY);
  749.     }
  750.     return code;
  751.     } else {
  752.     Tcl_AppendResult(interp, "bad option \"", argv[1],
  753.         "\": must be cget or configure", (char *) NULL);
  754.     return TCL_ERROR;
  755.     }
  756. }
  757.  
  758. /*
  759.  *----------------------------------------------------------------------
  760.  *
  761.  * ImgBmapGet --
  762.  *
  763.  *    This procedure is called for each use of a bitmap image in a
  764.  *    widget.
  765.  *
  766.  * Results:
  767.  *    The return value is a token for the instance, which is passed
  768.  *    back to us in calls to ImgBmapDisplay and ImgBmapFree.
  769.  *
  770.  * Side effects:
  771.  *    A data structure is set up for the instance (or, an existing
  772.  *    instance is re-used for the new one).
  773.  *
  774.  *----------------------------------------------------------------------
  775.  */
  776.  
  777. static ClientData
  778. ImgBmapGet(tkwin, masterData)
  779.     Tk_Window tkwin;        /* Window in which the instance will be
  780.                  * used. */
  781.     ClientData masterData;    /* Pointer to our master structure for the
  782.                  * image. */
  783. {
  784.     BitmapMaster *masterPtr = (BitmapMaster *) masterData;
  785.     BitmapInstance *instancePtr;
  786.  
  787.     /*
  788.      * See if there is already an instance for this window.  If so
  789.      * then just re-use it.
  790.      */
  791.  
  792.     for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
  793.         instancePtr = instancePtr->nextPtr) {
  794.     if (instancePtr->tkwin == tkwin) {
  795.         instancePtr->refCount++;
  796.         return (ClientData) instancePtr;
  797.     }
  798.     }
  799.  
  800.     /*
  801.      * The image isn't already in use in this window.  Make a new
  802.      * instance of the image.
  803.      */
  804.  
  805.     instancePtr = (BitmapInstance *) ckalloc(sizeof(BitmapInstance));
  806.     instancePtr->refCount = 1;
  807.     instancePtr->masterPtr = masterPtr;
  808.     instancePtr->tkwin = tkwin;
  809.     instancePtr->fg = NULL;
  810.     instancePtr->bg = NULL;
  811.     instancePtr->bitmap = None;
  812.     instancePtr->mask = None;
  813.     instancePtr->gc = None;
  814.     instancePtr->nextPtr = masterPtr->instancePtr;
  815.     masterPtr->instancePtr = instancePtr;
  816.     ImgBmapConfigureInstance(instancePtr);
  817.  
  818.     /*
  819.      * If this is the first instance, must set the size of the image.
  820.      */
  821.  
  822.     if (instancePtr->nextPtr == NULL) {
  823.     Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, masterPtr->width,
  824.         masterPtr->height);
  825.     }
  826.  
  827.     return (ClientData) instancePtr;
  828. }
  829.  
  830. /*
  831.  *----------------------------------------------------------------------
  832.  *
  833.  * ImgBmapDisplay --
  834.  *
  835.  *    This procedure is invoked to draw a bitmap image.
  836.  *
  837.  * Results:
  838.  *    None.
  839.  *
  840.  * Side effects:
  841.  *    A portion of the image gets rendered in a pixmap or window.
  842.  *
  843.  *----------------------------------------------------------------------
  844.  */
  845.  
  846. static void
  847. ImgBmapDisplay(clientData, display, drawable, imageX, imageY, width,
  848.     height, drawableX, drawableY)
  849.     ClientData clientData;    /* Pointer to BitmapInstance structure for
  850.                  * for instance to be displayed. */
  851.     Display *display;        /* Display on which to draw image. */
  852.     Drawable drawable;        /* Pixmap or window in which to draw image. */
  853.     int imageX, imageY;        /* Upper-left corner of region within image
  854.                  * to draw. */
  855.     int width, height;        /* Dimensions of region within image to draw. */
  856.     int drawableX, drawableY;    /* Coordinates within drawable that
  857.                  * correspond to imageX and imageY. */
  858. {
  859.     BitmapInstance *instancePtr = (BitmapInstance *) clientData;
  860.     int masking;
  861.  
  862.     /*
  863.      * If there's no graphics context, it means that an error occurred
  864.      * while creating the image instance so it can't be displayed.
  865.      */
  866.  
  867.     if (instancePtr->gc == None) {
  868.     return;
  869.     }
  870.  
  871.     /*
  872.      * If masking is in effect, must modify the mask origin within
  873.      * the graphics context to line up with the image's origin.
  874.      * Then draw the image and reset the clip origin, if there's
  875.      * a mask.
  876.      */
  877.  
  878.     masking = (instancePtr->mask != None) || (instancePtr->bg == NULL);
  879.     if (masking) {
  880.     XSetClipOrigin(display, instancePtr->gc, drawableX - imageX,
  881.         drawableY - imageY);
  882.     }
  883.     XCopyPlane(display, instancePtr->bitmap, drawable, instancePtr->gc,
  884.         imageX, imageY, (unsigned) width, (unsigned) height,
  885.         drawableX, drawableY, 1);
  886.     if (masking) {
  887.     XSetClipOrigin(display, instancePtr->gc, 0, 0);
  888.     }
  889. }
  890.  
  891. /*
  892.  *----------------------------------------------------------------------
  893.  *
  894.  * ImgBmapFree --
  895.  *
  896.  *    This procedure is called when a widget ceases to use a
  897.  *    particular instance of an image.
  898.  *
  899.  * Results:
  900.  *    None.
  901.  *
  902.  * Side effects:
  903.  *    Internal data structures get cleaned up.
  904.  *
  905.  *----------------------------------------------------------------------
  906.  */
  907.  
  908. static void
  909. ImgBmapFree(clientData, display)
  910.     ClientData clientData;    /* Pointer to BitmapInstance structure for
  911.                  * for instance to be displayed. */
  912.     Display *display;        /* Display containing window that used image. */
  913. {
  914.     BitmapInstance *instancePtr = (BitmapInstance *) clientData;
  915.     BitmapInstance *prevPtr;
  916.  
  917.     instancePtr->refCount--;
  918.     if (instancePtr->refCount > 0) {
  919.     return;
  920.     }
  921.  
  922.     /*
  923.      * There are no more uses of the image within this widget.  Free
  924.      * the instance structure.
  925.      */
  926.  
  927.     if (instancePtr->fg != NULL) {
  928.     Tk_FreeColor(instancePtr->fg);
  929.     }
  930.     if (instancePtr->bg != NULL) {
  931.     Tk_FreeColor(instancePtr->bg);
  932.     }
  933.     if (instancePtr->bitmap != None) {
  934.     XFreePixmap(display, instancePtr->bitmap);
  935.     }
  936.     if (instancePtr->mask != None) {
  937.     XFreePixmap(display, instancePtr->mask);
  938.     }
  939.     if (instancePtr->gc != None) {
  940.     Tk_FreeGC(display, instancePtr->gc);
  941.     }
  942.     if (instancePtr->masterPtr->instancePtr == instancePtr) {
  943.     instancePtr->masterPtr->instancePtr = instancePtr->nextPtr;
  944.     } else {
  945.     for (prevPtr = instancePtr->masterPtr->instancePtr;
  946.         prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) {
  947.         /* Empty loop body */
  948.     }
  949.     prevPtr->nextPtr = instancePtr->nextPtr;
  950.     }
  951.     ckfree((char *) instancePtr);
  952. }
  953.  
  954. /*
  955.  *----------------------------------------------------------------------
  956.  *
  957.  * ImgBmapDelete --
  958.  *
  959.  *    This procedure is called by the image code to delete the
  960.  *    master structure for an image.
  961.  *
  962.  * Results:
  963.  *    None.
  964.  *
  965.  * Side effects:
  966.  *    Resources associated with the image get freed.
  967.  *
  968.  *----------------------------------------------------------------------
  969.  */
  970.  
  971. static void
  972. ImgBmapDelete(masterData)
  973.     ClientData masterData;    /* Pointer to BitmapMaster structure for
  974.                  * image.  Must not have any more instances. */
  975. {
  976.     BitmapMaster *masterPtr = (BitmapMaster *) masterData;
  977.  
  978.     if (masterPtr->instancePtr != NULL) {
  979.     panic("tried to delete bitmap image when instances still exist");
  980.     }
  981.     masterPtr->tkMaster = NULL;
  982.     if (masterPtr->imageCmd != NULL) {
  983.     Tcl_DeleteCommand(masterPtr->interp,
  984.         Tcl_GetCommandName(masterPtr->interp, masterPtr->imageCmd));
  985.     }
  986.     if (masterPtr->data != NULL) {
  987.     ckfree(masterPtr->data);
  988.     }
  989.     if (masterPtr->maskData != NULL) {
  990.     ckfree(masterPtr->maskData);
  991.     }
  992.     Tk_FreeOptions(configSpecs, (char *) masterPtr, (Display *) NULL, 0);
  993.     ckfree((char *) masterPtr);
  994. }
  995.  
  996. /*
  997.  *----------------------------------------------------------------------
  998.  *
  999.  * ImgBmapCmdDeletedProc --
  1000.  *
  1001.  *    This procedure is invoked when the image command for an image
  1002.  *    is deleted.  It deletes the image.
  1003.  *
  1004.  * Results:
  1005.  *    None.
  1006.  *
  1007.  * Side effects:
  1008.  *    The image is deleted.
  1009.  *
  1010.  *----------------------------------------------------------------------
  1011.  */
  1012.  
  1013. static void
  1014. ImgBmapCmdDeletedProc(clientData)
  1015.     ClientData clientData;    /* Pointer to BitmapMaster structure for
  1016.                  * image. */
  1017. {
  1018.     BitmapMaster *masterPtr = (BitmapMaster *) clientData;
  1019.  
  1020.     masterPtr->imageCmd = NULL;
  1021.     if (masterPtr->tkMaster != NULL) {
  1022.     Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
  1023.     }
  1024. }
  1025.